/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package edu.ccut.titan.component;

import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;

import org.osgi.framework.Bundle;

import edu.ccut.titan.component.impl.TitanBundleInfo;
import edu.ccut.titan.component.impl.TitanLogicContext;
import edu.ccut.titan.component.impl.TitanParameter;
import edu.ccut.titan.component.impl.TitanParameterContext;
import edu.ccut.titan.component.loader.ComponentLoader;
import edu.ccut.titan.component.loader.DirectoryInfoLoader;

/**
 * Use Factory to create Object relate to Component
 * 
 * @author LeslieGu
 */
public abstract class ComponentFactory {

	/**
	 * Get all Directory information in Bundle root path
	 * 
	 * @param bundle
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static List<IDirectoryInfo> getDirectoryInfos(Bundle bundle) {
		List<IDirectoryInfo> directories = new LinkedList<IDirectoryInfo>();
		Enumeration<String> paths = bundle.getEntryPaths("/");
		while (paths.hasMoreElements()) {
			String path = paths.nextElement();

			if (path.endsWith("/")) {
				URL directoryInfoURL = bundle.getEntry(path
						+ IDirectoryInfo.TITAN_DIRECTORY_INFO_NAME);

				if (directoryInfoURL != null) {
					IDirectoryInfo directoryInfo = null;
					try {
						directoryInfo = ComponentFactory
								.getDirectoryInfo(
										bundle,
										path
												+ IDirectoryInfo.TITAN_DIRECTORY_INFO_NAME);
						directories.add(directoryInfo);
					} catch (TitanComponentException e) {
						e.printStackTrace();
					}
				}
			}
		}

		return directories;
	}

	/**
	 * Create a {@link IBaseComponentInfo} Object.
	 * <p>
	 * Note. the Object this method created didn't have any valid
	 * {@link IComponentInfo}, size is zero
	 * 
	 * @param bundle
	 * @return
	 */
	public static IBundleInfo createBundleComponentInfo(Bundle bundle) {
		return new TitanBundleInfo(bundle.getSymbolicName());
	}

	/**
	 * Create a {@link IParameter} by value and classType of value
	 * 
	 * @param value
	 * @param classType
	 * @return
	 */
	public static IParameter createParameter(Object value, Class<?> classType) {
		return new TitanParameter(value, classType);
	}

	/**
	 * Create a {@link IParameterContext} didn't have any {@link IParameter}
	 * 
	 * @return
	 */
	public static IParameterContext createParameterContext() {
		return new TitanParameterContext();
	}

	/**
	 * Create a {@link ILogicContext} by context unique id.
	 * <p>
	 * Id is equals to bundle symblicName
	 * 
	 * @param id
	 * @return
	 */
	public static ILogicContext createLogicContext(String id) {
		return new TitanLogicContext(id);
	}

	/**
	 * Load base {@link IComponentInfo} from a file path in a bundle.
	 * <p>
	 * In general. file is "META-INF/titan-component.xml"
	 * 
	 * @param bundle
	 * @param filePath
	 * @return
	 * @throws TitanComponentException
	 *             if load failed will throws this Exception.
	 */
	public static List<IComponentInfo> getComponentInfos(Bundle bundle,
			String filePath) throws TitanComponentException {
		return ComponentLoader.loadBaseComponent(bundle, filePath);
	}

	/**
	 * Load base {@link IComponentInfo} from input stream in a bundle.
	 * 
	 * @param bundle
	 * @param in
	 * @return
	 * @throws TitanComponentException
	 */
	public static List<IComponentInfo> getComponentInfos(Bundle bundle,
			InputStream in) throws TitanComponentException {
		return ComponentLoader.loadBaseComponent(bundle, in);
	}

	/**
	 * Load {@link IDirectoryInfo} from a file path in a bundle root directory.
	 * <p>
	 * In general, file name is ".titan"
	 * 
	 * @param bundle
	 * @param filePath
	 * @return
	 * @throws TitanComponentException
	 */
	public static IDirectoryInfo getDirectoryInfo(Bundle bundle, String filePath)
			throws TitanComponentException {
		return DirectoryInfoLoader.loadDirectoryInfo(bundle, filePath);
	}

	/**
	 * Load logic {@link IComponentInfo} from file path in a bundle.
	 * <p>
	 * In general, the postfix of file name is ".logic.xml".
	 * 
	 * @param bundle
	 * @param filePath
	 * @return
	 * @throws TitanComponentException
	 */
	public static IComponentInfo getLogicComponentInfo(Bundle bundle,
			String filePath) throws TitanComponentException {
		return ComponentLoader.loadLogicComponentInfo(bundle, filePath);
	}

	/**
	 * Load logic {@link IComponentInfo} from input stream in a bundle.
	 * 
	 * @param bundle
	 * @param in
	 * @return
	 * @throws TitanComponentException
	 */
	public static IComponentInfo getLogicComponentInfo(Bundle bundle,
			InputStream in) throws TitanComponentException {
		return ComponentLoader.loadLogicComponentInfo(bundle, in);
	}

	/**
	 * Load action {@link IComponentInfo} from file path in a bundle.
	 * <p>
	 * In general, the postfix of file name is ".action.xml".
	 * 
	 * @param bundle
	 * @param filePath
	 * @return
	 * @throws TitanComponentException
	 */
	public static IComponentInfo getActionComponentInfo(Bundle bundle,
			String filePath) throws TitanComponentException {
		return ComponentLoader.loadActionComponentInfo(bundle, filePath);
	}

	/**
	 * Load action {@link IComponentInfo} from input stream in a bundle.
	 * 
	 * @param bundle
	 * @param in
	 * @return
	 * @throws TitanComponentException
	 */
	public static IComponentInfo getActionComponentInfo(Bundle bundle,
			InputStream in) throws TitanComponentException {
		return ComponentLoader.loadActionComponentInfo(bundle, in);
	}
}
